package com.thientan.controller

import java.text.SimpleDateFormat
import java.util.Map;

import org.hibernate.FetchMode
import org.hibernate.StaleObjectStateException
import org.hibernate.exception.ConstraintViolationException
import org.springframework.dao.DataIntegrityViolationException
import org.springframework.dao.OptimisticLockingFailureException

import grails.converters.JSON

import com.thientan.export.ExportType;
import com.thientan.model.DuLieuHeThong
import com.thientan.model.HopDong
import com.thientan.model.KhachHang
import com.thientan.model.NhanVien
import com.thientan.model.enums.LoaiDuLieu
import com.thientan.model.enums.LoaiNhanVien
import com.thientan.model.enums.TrangThaiHopDong
import com.thientan.service.HopDongService
import com.thientan.utils.Constants
import com.thientan.utils.Utility;


class HopDongController extends AbstractBaseController {
	HopDongService hopDongService

	@Override
	public Class getDomainClass() {
		return HopDong.class
	}

	@Override
	public String getDomainName() {
		message(code : "default.thientan.messages.hopDong")
	}

	@Override
	public Object getDomainService() {
		return hopDongService
	}

	@Override
	public String getDisplayFieldName() {
		"maHd"
	}

	def initData = {
		Map result = ["success" : true]
		List<NhanVien> doiTruongs = NhanVien.findAllByDoiTruongIsNullAndLoaiNhanVien(LoaiNhanVien.BAN_HANG)
		List<NhanVien> nvBan = NhanVien.findAllByLoaiNhanVien(LoaiNhanVien.BAN_HANG)
		List<NhanVien> thuNgans = NhanVien.findAllByLoaiNhanVien(LoaiNhanVien.THU_NGAN)
		List<DuLieuHeThong> tinhThanhs = DuLieuHeThong.findAllByLoaiDuLieu(LoaiDuLieu.TINH_THANH)
		result.putAt("doiTruong", extractPropertiesAsMaps(doiTruongs, ["id", "maNv"]))
		result.putAt("nvBan", extractPropertiesAsMaps(nvBan + thuNgans, ["id", "maNv", "doiTruong.id"]))
		result.putAt("thuNgan", extractPropertiesAsMaps(thuNgans, ["id", "maNv"]))
		result.putAt("tinhThanh", extractPropertiesAsMaps(tinhThanhs, ["maDuLieu", "giaTri"]))

		if (params["isSearchScreen"]) {
			List trangThais = TrangThaiHopDong.values().collect {
				["value" : it.name(), "text" : it.toString()]
			}
			result.putAt("trangThais", trangThais)
		}
		render result as JSON
	}

	def reloadQuanHuyenByThanhPho = {
		List<DuLieuHeThong> quanHuyens = DuLieuHeThong.findAllByLoaiDuLieuAndMaDuLieuLienQuan(
				LoaiDuLieu.QUAN_HUYEN, params["maTinh"])
		render extractPropertiesAsMaps(quanHuyens, ["maDuLieu", "giaTri"]) as JSON
	}

	def reloadPhuongXaByQuanHuyen = {
		List<DuLieuHeThong> phuongXas = DuLieuHeThong.findAllByLoaiDuLieuAndMaDuLieuLienQuan(LoaiDuLieu.PHUONG_XA, params["maQuanHuyen"])
		render extractPropertiesAsMaps(phuongXas, ["maDuLieu", "giaTri"]) as JSON
	}

	@Override
	protected Map prepareParams() {
		Map parameters = params
		if(params["thuTienNgay"]) {
			parameters.put("trangThai", TrangThaiHopDong.TIEN_MAT)
			parameters.put("tienDaThu", 0)
			parameters.put("tienConLai", 0)
		}
		parameters.putAt("giaTri", Double.valueOf(parameters["giaTri"]) * Constants.RATE)
		parameters.putAt("tienTraTruoc", Double.valueOf(parameters["tienTraTruoc"]) * Constants.RATE)
		parameters.putAt("tienDaThu", Double.valueOf(parameters["tienDaThu"]) * Constants.RATE)
		parameters.putAt("tienConLai", Double.valueOf(parameters["tienConLai"]) * Constants.RATE)
		if (parameters["tienConLai"] == 0 && actionName == "save" && !params["thuTienNgay"]) {
			parameters.put("trangThai", TrangThaiHopDong.KET_THUC)
		}
		
		parameters.putAt("maHd", params["maHd"].toUpperCase())
		parameters.put("nvDoiTruong.id", params["nvDoiTruong-id"])
		parameters.put("nvBan1.id", params["nvBan1-id"])
		parameters.put("nvBan2.id", params["nvBan2-id"])
		parameters.put("nvThuNgan.id", params["nvThuNgan-id"])
		parameters.remove("nvDoiTruong-id")
		parameters.remove("nvBan1-id")
		parameters.remove("nvBan2-id")
		parameters.remove("nvThuNgan-id")
		parameters.putAt("ngayBan", new SimpleDateFormat(Constants.DEFAULT_DATE_FORMAT).parse(params["ngayBan"]))
		
		if (!params["id"]) {
			KhachHang kh = new KhachHang(parameters)
			parameters.putAt("khachHang", kh)
		}
		parameters
	}
	
	def edit = {
		String msg
		def objectId = params['id']
		HopDong hd = domainClass.get(objectId)
		
		// Binding params.
		
		Map returnMap = [:]
		try {
			Map parameters = prepareParams()
			hd.properties = parameters
			KhachHang kh = hd.khachHang
			kh.properties = parameters
			def savedObject = hopDongService.edit(hd, kh)
			if(!hd.errors.allErrors){
				// Update editing object in session
				putOrUpdateToSession(savedObject, savedObject.id)
				msg = message(code : 'default.thientan.messages.saveSuccess',
						args : [
							domainName,
							hd.getAt(displayFieldName)
						])
				returnMap = getFormMessage(true, "info", msg, null)
				returnMap += renderSavedDomain(hd)
			} else {
				log.warn('Binding/Validation errors happended during saving: ' + hd.errors.allErrors)
				def errors = getErrorList(hd.errors.allErrors, domainName)
				msg = message(code : "default.action.save.fail.who",
						args : [
							getDomainName(),
							params.getAt(displayFieldName)
						])
				returnMap = getFormMessage(false, "error", msg, errors)
			}
		} catch(OptimisticLockingFailureException ex) {
			log.error("OptimisticLockingFailureException happened during saving", ex)
			returnMap = produceConcurrentUpdateMessage(displayFieldName)
		} catch(StaleObjectStateException ex) {
			log.error("StaleObjectStateException happened during saving", ex)
			returnMap = produceConcurrentUpdateMessage(displayFieldName)
		} catch(DataIntegrityViolationException ex) {
			log.error("DataIntegrityViolationException happened during saving", ex)
			returnMap = produceConstraintViolationMessage()
		} catch(ConstraintViolationException ex) {
			log.error("ConstraintViolationException happened during saving", ex)
			returnMap = produceConstraintViolationMessage()
		} catch(Exception ex){
			log.error("Unexpected error happened during saving", ex)
			returnMap = handleSaveExceptions(ex, returnMap)
		}
		returnMap["customInfo"] = customInfo
		render (returnMap as JSON)
	}	
	

	def requestHdInfo = {
		String maHd = params["maHd"]
		List<HopDong> hds = HopDong.withCriteria {
			if (params["isEditHd"]) {
				fetchMode("khachHang", FetchMode.JOIN)
			}
			eq("maHd", maHd.toUpperCase())
		}
		Map result = [:]
		if(hds) {
			HopDong hd = hds.first()
			if (Boolean.valueOf(params["isEditHd"]) == true) {
				Map data = extractPropertiesAsMap(hd, [
					"id",
					"maHd",
					"nvBan1.maNv",
					"nvBan2.maNv",
					"nvDoiTruong.maNv",
					"nvThuNgan.maNv",
					"ngayBan",
					"giaTri",
					"tienTraTruoc",
					"tienDaThu",
					"tienConLai",
					"trangThaiText",
					"daGiaoPhieu",
					"khachHang.hoTen",
					"khachHang.diaChi",
					"khachHang.dienThoai",
					"khachHang.phuongXa",
					"khachHang.quanHuyen",
					"khachHang.tinhThanh"
				])
				String query = "from DuLieuHeThong d where d.loaiDuLieu = ? " + 
							   "and d.maDuLieuLienQuan = (select t.maDuLieu from DuLieuHeThong t where t.giaTri=?) " + 
							   "order by d.giaTri" 
				List<DuLieuHeThong> qhs = DuLieuHeThong.findAll(query, [LoaiDuLieu.QUAN_HUYEN, hd.khachHang.tinhThanh])
				List<DuLieuHeThong> pxs = DuLieuHeThong.findAll(query, [LoaiDuLieu.PHUONG_XA, hd.khachHang.quanHuyen])
				data.putAt("quanHuyen", extractPropertiesAsMaps(qhs, ["maDuLieu", "giaTri"]))
				data.putAt("phuongXa", extractPropertiesAsMaps(pxs, ["maDuLieu", "giaTri"]))
				result = ["success" : true, "data" : data]
			} else {
				if (!hd.nvThuNgan) {
					result = ["success" : false, 
							  "msg" : message(code : "default.thientan.messages.notAssignThuNgan", args : null)]
				} else if (!hd.daGiaoPhieu && hd.trangThai == TrangThaiHopDong.DANG_TRA_GOP) {
					result = ["success" : false,
							 "msg" : message(code : "default.thientan.messages.notGiaoPhieu", args : null)]
				} else {
					Map data = extractPropertiesAsMap(hd, [
						"id",
						"maHd",
						"nvBan1.maNv",
						"nvBan2.maNv",
						"nvDoiTruong.maNv",
						"nvThuNgan.maNv",
						"ngayBan",
						"giaTri",
						"tienTraTruoc",
						"tienDaThu",
						"tienConLai",
						"trangThaiText"
					])
					result = ["success" : true, "data" : data]
				}
			}
		} else {
			result = ["success" : false, 
					  "msg" : message(code : "default.thientan.messages.hopDongNotExist", args : null)]
		}
		render result as JSON
	}
	
	def checkStatus = {
		HopDong hd = HopDong.get(params["id"])
		Map result = ['isTraGop' : hd.trangThai == TrangThaiHopDong.DANG_TRA_GOP]
		render result as JSON
	}
	
	@Override
	protected Map buildExportData(Map exportParams){
		String barcodeBasePath = servletContext.getRealPath("") + File.separator;
		String barcodePath = barcodeBasePath + Constants.BARCODE_FILE_PATH
		Long hopDongId = params['id'] as Long
		// Collect hopDong infor to export Phieu Thu
		HopDong hopDong = HopDong.get(hopDongId)
		String maHopDong = hopDong?.maHd ?: ""
		// Generate barcode
		Utility.generateBarcode(maHopDong, barcodePath)
		// Prepare data for export
		List phieuThuData = (1..24).collect{item ->
			['stt' : item,
			 'ngaytra': "", 'tienthu': "",'tienconno': "",'khky': "",'tnky': "", 'tenthungan': ""
			]
		}
		
		return ['data' : phieuThuData,
				'ngayin' : new SimpleDateFormat(Constants.DEFAULT_DATE_FORMAT).format(Calendar.getInstance().getTime()),
				'tenkhachhang' : hopDong?.khachHang.hoTen,
				'diachi' : hopDong?.khachHang.fullDiaChi,
				'dienthoai' : hopDong?.khachHang.dienThoai,
				'tongtien' : Utility.moneyFormat(hopDong?.giaTri ?: 0),
				'doitruong' : hopDong?.nvDoiTruong?.maNv,
				'nv1' : hopDong?.nvBan1?.maNv ?: "",
				'nv2' : hopDong?.nvBan2?.maNv ?: "",
				'tratruoc' : Utility.moneyFormat(hopDong?.tienTraTruoc ?: 0),
				'conlai' : Utility.moneyFormat(hopDong?.tienConLai ?: 0),
				'mahopdong' : maHopDong,
				'mavachpath' : barcodePath,
				'logopath' : barcodeBasePath + Constants.LOGO_FILE_PATH
				]
		
		
	}
	
	@Override
	protected String getExportFileName(){
		"PhieuThu"
	}
	
	@Override
	protected ExportType getExportType(){
		ExportType.PDF
	}
}